using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;

namespace CompanyX.TechnicalArchitecture.PerfContext
{
    /// <summary>
    /// Enables defining custom configuration section for performance context
    /// <code>
    /// &lt;configSections&gt;
    ///     &lt;section name="appSpecificPerfContexts" type="CompanyX.TechnicalArchitecture.PerfContext.PerfContextsConfig, CompanyX.TechnicalArchitecture, PublicKeyToken="1BD8D1813D39DDE3" Version="1.0.0.0" Culture="neutral"/&gt;
    /// &lt;/configSections&gt;
    /// &lt;appSpecificPerfContexts&gt;
    ///     &lt;perfContexts&gt;
    ///         &lt;clear /&gt;
    ///         &lt;add contextName="SampleTransaction1" categoryName="RnD.PerformanceObject1" executionTimeCounter="true" throughputCounter="true" executionCountCounter="true" executionErrorCountCounter="true" instanceNames="default" /&gt;
    ///         &lt;add contextName="SampleTransaction2" categoryName="RnD.PerformanceObject2" executionTimeCounter="true" instanceNames="default,,temp1,temp2" /&gt;
    ///     &lt;/perfContexts&gt;
    /// &lt;/appSpecificPerfContexts&gt;
    /// </code>
    /// </summary>
    public sealed class PerfContextsConfig : ConfigurationSection
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public PerfContextsConfig()
        {
        }

        /// <summary>
        /// Collection of PerfContext
        /// </summary>
        [ConfigurationProperty("perfContexts", IsDefaultCollection = false)]
        [ConfigurationCollection(typeof(PerfContextConfigList), AddItemName = "add", ClearItemsName = "clear", RemoveItemName = "remove")]
        public PerfContextConfigList PerfContexts
        {
            get
            {
                return (PerfContextConfigList)this["perfContexts"];
            }
            set
            {
                this["perfContexts"] = value;
            }
        }
    }

    /// <summary>
    /// Represents a collection of PerfContext elements defined in the configuration file
    /// </summary>
    public class PerfContextConfigList : ConfigurationElementCollection
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public PerfContextConfigList()
        {
            PerfContextConfig provider = (PerfContextConfig)CreateNewElement();
            Add(provider);
        }

        /// <summary>
        /// Collection type
        /// </summary>
        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.AddRemoveClearMap;
            }
        }

        /// <summary>
        /// Creates a new provider configuration element
        /// </summary>
        /// <returns></returns>
        protected override ConfigurationElement CreateNewElement()
        {
            return new PerfContextConfig();
        }

        /// <summary>
        /// Retrieves the provider configuration element key (name)
        /// </summary>
        /// <param name="element">Provider configuration element to get the key for</param>
        /// <returns>Key value</returns>
        protected override Object GetElementKey(ConfigurationElement element)
        {
            return ((PerfContextConfig)element).ContextName;
        }

        /// <summary>
        /// Accessor for provider configuration element
        /// </summary>
        /// <param name="index">Element to access by index</param>
        /// <returns>Provider configuration element</returns>
        public PerfContextConfig this[int index]
        {
            get
            {
                return (PerfContextConfig)BaseGet(index);
            }
            set
            {
                if (BaseGet(index) != null)
                {
                    BaseRemoveAt(index);
                }
                BaseAdd(index, value);
            }
        }

        /// <summary>
        /// Accessor for provider configuration element
        /// </summary>
        /// <param name="Name">Element to access by key name</param>
        /// <returns>Provider configuration element</returns>
        new public PerfContextConfig this[string Name]
        {
            get
            {
                return (PerfContextConfig)BaseGet(Name);
            }
        }

        /// <summary>
        /// Retrieves the index of the provider configuration element
        /// </summary>
        /// <param name="provider">Provider configuration element</param>
        /// <returns>Index of the element</returns>
        public int IndexOf(PerfContextConfig provider)
        {
            return BaseIndexOf(provider);
        }

        /// <summary>
        /// Adds a provider configuration element
        /// </summary>
        /// <param name="provider">Provider configuration element</param>
        public void Add(PerfContextConfig provider)
        {
            BaseAdd(provider);
        }

        /// <summary>
        /// Wrapper
        /// </summary>
        /// <param name="element"></param>
        protected override void BaseAdd(ConfigurationElement element)
        {
            BaseAdd(element, false);
        }

        /// <summary>
        /// Removes a provider configuration element
        /// </summary>
        /// <param name="provider">Provider configuration element</param>
        public void Remove(PerfContextConfig provider)
        {
            if (BaseIndexOf(provider) >= 0)
                BaseRemove(provider.ContextName);
        }

        /// <summary>
        /// Removes a provider configuration element
        /// </summary>
        /// <param name="index">Element index</param>
        public void RemoveAt(int index)
        {
            BaseRemoveAt(index);
        }

        /// <summary>
        /// Removes a provider configuration element
        /// </summary>
        /// <param name="name">Element name</param>
        public void Remove(string name)
        {
            BaseRemove(name);
        }

        /// <summary>
        /// Clears all provider configuration elements
        /// </summary>
        public void Clear()
        {
            BaseClear();
        }
    }

    /// <summary>
    /// PerfContext configuration element
    /// </summary>
    public sealed class PerfContextConfig : ConfigurationElement
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public PerfContextConfig()
        {
        }

        /// <summary>
        /// Unique context name (alpha-numeric)
        /// </summary>
        [ConfigurationProperty("contextName", IsRequired = true)]
        [StringValidator(InvalidCharacters = "~!@#$%^&*()[]{}/;'\"|\\.,<>?_=+")]
        public string ContextName
        {
            get { return (string)this["contextName"]; }
            set { this["contextName"] = value; }
        }

        /// <summary>
        /// Name of the performance object
        /// </summary>
        [ConfigurationProperty("categoryName", IsRequired = true)]
        public string CategoryName
        {
            get { return (string)this["categoryName"]; }
            set { this["categoryName"] = value; }
        }

        /// <summary>
        /// Flag to indicate execution time counter for the context
        /// </summary>
        [ConfigurationProperty("executionTimeCounter", IsRequired = true)]
        public bool ExecutionTimeCounter
        {
            get { return (bool)this["executionTimeCounter"]; }
            set { this["executionTimeCounter"] = value; }
        }

        /// <summary>
        /// Flag to indicate through put counter for the context
        /// </summary>
        [ConfigurationProperty("throughputCounter", IsRequired = false, DefaultValue = false)]
        public bool ThroughputCounter
        {
            get { return (bool)this["throughputCounter"]; }
            set { this["throughputCounter"] = value; }
        }

        /// <summary>
        /// Flag to indicate execution count counter for the context
        /// </summary>
        [ConfigurationProperty("executionCountCounter", IsRequired = false, DefaultValue = false)]
        public bool ExecutionCountCounter
        {
            get { return (bool)this["executionCountCounter"]; }
            set { this["executionCountCounter"] = value; }
        }

        /// <summary>
        /// Flag to indicate execution error count counter for the context
        /// </summary>
        [ConfigurationProperty("executionErrorCountCounter", IsRequired = false, DefaultValue = false)]
        public bool ExecutionErrorCountCounter
        {
            get { return (bool)this["executionErrorCountCounter"]; }
            set { this["executionErrorCountCounter"] = value; }
        }

        /// <summary>
        /// Comma delimited list of instance names
        /// </summary>
        [ConfigurationProperty("instanceNames", IsRequired = false, DefaultValue = "default")]
        public string InstanceNames
        {
            get { return (string)this["instanceNames"]; }
            set { this["instanceNames"] = value; }
        }
    }
}
